
package com.huaweicloud.saaslanding.install.json;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.huaweicloud.saaslanding.basic.constant.KafkaConstant;
import com.huaweicloud.saaslanding.basic.constant.UrlConstant;
import com.huaweicloud.saaslanding.basic.database.properties.MultiTenantType;
import com.huaweicloud.saaslanding.basic.enumeration.ComponentLabelEnum;
import com.huaweicloud.saaslanding.basic.enumeration.ConfigFilePrefixEnum;
import com.huaweicloud.saaslanding.basic.enumeration.FileExtensionEnum;
import com.huaweicloud.saaslanding.basic.enumeration.RedisServerTypeEnum;
import com.huaweicloud.saaslanding.basic.enumeration.ServiceManageFrameTypeEnum;
import com.huaweicloud.saaslanding.basic.exception.BizException;
import com.huaweicloud.saaslanding.basic.exception.code.ExceptionCode;
import com.huaweicloud.saaslanding.basic.routelink.constant.RouteLinkConstant;
import com.huaweicloud.saaslanding.basic.utils.ConfigNameUtil;
import com.huaweicloud.saaslanding.basic.utils.ResourceNamingUtil;
import com.huaweicloud.saaslanding.basic.utils.YamlUtil;
import com.huaweicloud.saaslanding.dao.common.entity.cloudservice.RedisInfo;
import com.huaweicloud.saaslanding.dao.common.repository.cloudservice.RedisInfoBaseMapper;
import com.huaweicloud.saaslanding.huawei.cse.request.CseConfigCreateRequest;
import com.huaweicloud.saaslanding.install.dto.ServiceManageFrameworkDto;
import com.huaweicloud.saaslanding.install.properties.Dcs;
import com.huaweicloud.saaslanding.install.properties.Lts;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.text.StringSubstitutor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.yaml.snakeyaml.Yaml;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * CSE 相关请求体构建
 *
 * @since 2022-07-29
 */
@Slf4j
@Component
public class ServiceManageFrameworkRequestBody {

    public static final String SWAGGER_API = "v3/api-docs";

    public static final String SWAGGER_ROUTES_NAME = "-doc";

    @Resource
    private RedisInfoBaseMapper redisInfoBaseMapper;

    @Resource
    private Environment environment;

    @Resource
    private Dcs dcs;

    @Resource
    private Lts lts;

    @Value("${saaslanding-install.idaas.type}")
    private String idaasType;

    @Value("${saaslanding-install.swagger.enabled:false}")
    private Boolean swaggerEnabled;

    /**
     * 【基础配置项】
     * 【请求体】，用于创建CSE微服务级配置项
     *
     * @param serviceManageFrameworkDto 配置信息
     * @return String
     */
    public CseConfigCreateRequest createBasicConfigJson(ServiceManageFrameworkDto serviceManageFrameworkDto) {

        CseConfigCreateRequest configCreateRequest =
            getCseBaseRequestJSONObject(serviceManageFrameworkDto, ConfigFilePrefixEnum.BASIC.getPrefix());

        if (ComponentLabelEnum.GATEWAY.getLabel().equals(serviceManageFrameworkDto.getLabel())) {
            configCreateRequest.setValue(initGateWayValue(serviceManageFrameworkDto));
        } else {
            configCreateRequest.setValue(initValue(serviceManageFrameworkDto));
        }

        return configCreateRequest;
    }

    /**
     * 【基础配置项】
     * 【请求体】，用于创建CSE微服务级配置项
     *
     * @param serviceManageFrameworkDto 配置信息
     * @return String
     */
    public String createNacosBasicConfigJson(ServiceManageFrameworkDto serviceManageFrameworkDto) {

        if ("GATEWAY".equals(serviceManageFrameworkDto.getLabel())) {
            return initGateWayValue(serviceManageFrameworkDto);
        } else {
            return initValue(serviceManageFrameworkDto);
        }
    }

    /**
     * 构造
     * 【网关】
     * 【配置数据】
     *
     * @param serviceManageFrameworkDto 配置信息
     * @return JSONObject
     */
    public String initGateWayValue(ServiceManageFrameworkDto serviceManageFrameworkDto) {

        JSONObject main = new JSONObject();
        main.put("allow-bean-definition-overriding", true);

        JSONObject spring = new JSONObject();
        spring.put("main", main);
        spring.put("data", initSpringData());

        JSONObject servlet = new JSONObject();
        servlet.put("context-path", "/");

        JSONObject server = new JSONObject();
        server.put("port", serviceManageFrameworkDto.getServerPort());
        server.put("servlet", servlet);

        JSONObject webmvc = new JSONObject();
        webmvc.put("enabled", false);

        JSONObject saaslanding = new JSONObject();
        saaslanding.put("platformAppName", serviceManageFrameworkDto.getRdsDatabase());
        saaslanding.put("webmvc", webmvc);
        JSONObject apiSwitchJson = new JSONObject();
        apiSwitchJson.put("apiSwitch", true);
        saaslanding.put("apiAuth", apiSwitchJson);
        JSONObject databaseJson = new JSONObject();
        databaseJson.put("database", serviceManageFrameworkDto.getAppName());
        saaslanding.put("mysql", databaseJson);

        JSONObject org = new JSONObject();
        String prefixCode = ResourceNamingUtil.getPrefixCode();
        org.put("prefixCode", prefixCode);
        saaslanding.put("org", org);

        JSONObject value = new JSONObject();
        value.put("saaslanding", saaslanding);
        value.put("spring", spring);
        value.put("server", server);
        value.put("logging", initLogging());

        return YamlUtil.jsonToYaml(value);
    }

    /**
     * 构造
     * 网关
     * routes
     *
     * @param serviceManageFrameworkDto 配置信息
     * @return List<JSONObject>
     */
    private List<JSONObject> initRoutes(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        JSONObject login = getLogin(serviceManageFrameworkDto);

        JSONObject tenant = getTenantList(serviceManageFrameworkDto);

        JSONObject authority = getComponentRoutes(serviceManageFrameworkDto,
            serviceManageFrameworkDto.getAuthorityName(), serviceManageFrameworkDto.getAuthorityPath());

        JSONObject deployment = getNoHeaderComponentRoutes(serviceManageFrameworkDto,
            serviceManageFrameworkDto.getDeploymentName(), serviceManageFrameworkDto.getDeploymentPath());

        JSONObject upgrade = getComponentRoutes(serviceManageFrameworkDto, serviceManageFrameworkDto.getUpgradeName(),
            serviceManageFrameworkDto.getUpgradePath());

        JSONObject maintenance = getComponentRoutes(serviceManageFrameworkDto,
            serviceManageFrameworkDto.getMaintenanceName(), serviceManageFrameworkDto.getMaintenancePath());

        JSONObject auth = getNoHeaderComponentRoutes(serviceManageFrameworkDto, serviceManageFrameworkDto.getAuthName(),
            serviceManageFrameworkDto.getAuthPath());

        JSONObject integrated = getNoHeaderComponentRoutes(serviceManageFrameworkDto,
            serviceManageFrameworkDto.getIntegratedName(), serviceManageFrameworkDto.getIntegratedPath());

        JSONObject log = getComponentRoutes(serviceManageFrameworkDto, serviceManageFrameworkDto.getLogName(),
            serviceManageFrameworkDto.getLogPath());

        JSONObject measurement = getComponentRoutes(serviceManageFrameworkDto,
            serviceManageFrameworkDto.getMeasurementName(), serviceManageFrameworkDto.getMeasurementPath());

        JSONObject operation = getComponentRoutes(serviceManageFrameworkDto,
            serviceManageFrameworkDto.getOperationName(), serviceManageFrameworkDto.getOperationPath());

        JSONObject job = getComponentRoutes(serviceManageFrameworkDto, serviceManageFrameworkDto.getJobName(),
            serviceManageFrameworkDto.getJobPath());

        List<JSONObject> routes = new ArrayList<>();
        routes.add(tenant);
        routes.add(login);
        routes.add(authority);
        routes.add(deployment);
        routes.add(upgrade);
        routes.add(maintenance);
        routes.add(integrated);
        routes.add(log);
        routes.add(measurement);
        routes.add(operation);
        routes.add(job);
        routes.add(auth);

        if (swaggerEnabled) {
            JSONObject tenantDoc = getNoHeaderComponentRoutes(serviceManageFrameworkDto.getAppName(),
                serviceManageFrameworkDto.getTenantName(),
                serviceManageFrameworkDto.getTenantPath().replace("**", SWAGGER_API + "/**"), serviceManageFrameworkDto.getTenantName() + SWAGGER_ROUTES_NAME);
            routes.add(tenantDoc);

            JSONObject authorityDoc = getNoHeaderComponentRoutes(serviceManageFrameworkDto.getAppName(),
                serviceManageFrameworkDto.getAuthorityName(),
                serviceManageFrameworkDto.getAuthorityPath().replace("**", SWAGGER_API + "/**"), serviceManageFrameworkDto.getAuthorityName() + SWAGGER_ROUTES_NAME);
            routes.add(authorityDoc);

            JSONObject deploymentDoc = getNoHeaderComponentRoutes(serviceManageFrameworkDto.getAppName(),
                serviceManageFrameworkDto.getDeploymentName(),
                serviceManageFrameworkDto.getDeploymentPath().replace("**", SWAGGER_API + "/**"), serviceManageFrameworkDto.getDeploymentName() + SWAGGER_ROUTES_NAME);
            routes.add(deploymentDoc);

            JSONObject upgradeDoc = getNoHeaderComponentRoutes(serviceManageFrameworkDto.getAppName(),
                serviceManageFrameworkDto.getUpgradeName(),
                serviceManageFrameworkDto.getUpgradePath().replace("**", SWAGGER_API + "/**"), serviceManageFrameworkDto.getUpgradeName() + SWAGGER_ROUTES_NAME);
            routes.add(upgradeDoc);

            JSONObject maintenanceDoc = getNoHeaderComponentRoutes(serviceManageFrameworkDto.getAppName(),
                serviceManageFrameworkDto.getMaintenanceName(),
                serviceManageFrameworkDto.getMaintenancePath().replace("**", SWAGGER_API + "/**"), serviceManageFrameworkDto.getMaintenanceName() + SWAGGER_ROUTES_NAME);
            routes.add(maintenanceDoc);

            JSONObject integratedDoc = getNoHeaderComponentRoutes(serviceManageFrameworkDto.getAppName(),
                serviceManageFrameworkDto.getIntegratedName(),
                serviceManageFrameworkDto.getIntegratedPath().replace("**", SWAGGER_API + "/**"), serviceManageFrameworkDto.getIntegratedName() + SWAGGER_ROUTES_NAME);
            routes.add(integratedDoc);

            JSONObject logDoc = getNoHeaderComponentRoutes(serviceManageFrameworkDto.getAppName(),
                serviceManageFrameworkDto.getLogName(),
                serviceManageFrameworkDto.getLogPath().replace("**", SWAGGER_API + "/**"), serviceManageFrameworkDto.getLogName() + SWAGGER_ROUTES_NAME);
            routes.add(logDoc);

            JSONObject measurementDoc = getNoHeaderComponentRoutes(serviceManageFrameworkDto.getAppName(),
                serviceManageFrameworkDto.getMeasurementName(),
                serviceManageFrameworkDto.getMeasurementPath().replace("**", SWAGGER_API + "/**"), serviceManageFrameworkDto.getMeasurementName() + SWAGGER_ROUTES_NAME);
            routes.add(measurementDoc);

            JSONObject operationDoc = getNoHeaderComponentRoutes(serviceManageFrameworkDto.getAppName(),
                serviceManageFrameworkDto.getOperationName(),
                serviceManageFrameworkDto.getOperationPath().replace("**", SWAGGER_API + "/**"), serviceManageFrameworkDto.getOperationName() + SWAGGER_ROUTES_NAME);
            routes.add(operationDoc);

            JSONObject jobDoc = getNoHeaderComponentRoutes(serviceManageFrameworkDto.getAppName(),
                serviceManageFrameworkDto.getJobName(),
                serviceManageFrameworkDto.getJobPath().replace("**", SWAGGER_API + "/**"), serviceManageFrameworkDto.getJobName() + SWAGGER_ROUTES_NAME);
            routes.add(jobDoc);

            JSONObject authDoc = getNoHeaderComponentRoutes(serviceManageFrameworkDto.getAppName(),
                serviceManageFrameworkDto.getAuthName(),
                serviceManageFrameworkDto.getAuthPath().replace("**", SWAGGER_API + "/**"), serviceManageFrameworkDto.getAuthName() + SWAGGER_ROUTES_NAME);
            routes.add(authDoc);
        }

        return routes;
    }

    private JSONObject getComponentRoutes(ServiceManageFrameworkDto serviceManageFrameworkDto, String name,
        String path) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("id", name);
        jsonObject.put("uri", "lb://" + serviceManageFrameworkDto.getAppName() + "." + name);
        List<String> list = new ArrayList<>();
        list.add("Path=" + path);
        list.add("Header=tenant, " + serviceManageFrameworkDto.getAppName());
        jsonObject.put("predicates", list);
        return jsonObject;
    }

    private JSONObject getNoHeaderComponentRoutes(ServiceManageFrameworkDto serviceManageFrameworkDto, String name,
        String path) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("id", name);
        jsonObject.put("uri", "lb://" + serviceManageFrameworkDto.getAppName() + "." + name);
        List<String> list = new ArrayList<>();
        list.add("Path=" + path);
        jsonObject.put("predicates", list);
        return jsonObject;
    }

    private JSONObject getNoHeaderComponentRoutes(String appName, String name, String path) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("id", name);
        jsonObject.put("uri", "lb://" + appName + "." + name);
        List<String> list = new ArrayList<>();
        list.add("Path=" + path);
        jsonObject.put("predicates", list);
        return jsonObject;
    }

    private JSONObject getNoHeaderComponentRoutes(String appName, String name, String path, String id) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("id", id);
        jsonObject.put("uri", "lb://" + appName + "." + name);
        List<String> list = new ArrayList<>();
        list.add("Path=" + path);
        jsonObject.put("predicates", list);
        return jsonObject;
    }

    private JSONObject getTenantList(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        List<String> tenantList = new ArrayList<>();
        tenantList.add("Path=" + serviceManageFrameworkDto.getTenantPath());
        tenantList.add("Header=tenant, " + serviceManageFrameworkDto.getAppName());
        JSONObject tenant = new JSONObject();
        tenant.put("id", serviceManageFrameworkDto.getTenantName());
        tenant.put("uri",
            "lb://" + serviceManageFrameworkDto.getAppName() + "." + serviceManageFrameworkDto.getTenantName());
        tenant.put("predicates", tenantList);
        return tenant;
    }

    private JSONObject getLogin(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        JSONObject login = new JSONObject();
        login.put("id", serviceManageFrameworkDto.getTenantName() + "-login");
        login.put("uri",
            "lb://" + serviceManageFrameworkDto.getAppName() + "." + serviceManageFrameworkDto.getTenantName());
        List<String> list = new ArrayList<>();
        list.add("Path=/saaslandingTenant/origin/**");
        login.put("predicates", list);
        return login;
    }

    /**
     * 【除网关外微服务】
     * 【配置数据】
     *
     * @param serviceManageFrameworkDto
     *        配置信息
     * @return JSONObject
     */
    private String initValue(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        JSONObject value = new JSONObject();
        value.put("logging", initLogging());
        value.put("mybatis-plus", initMybatisPlus(serviceManageFrameworkDto));
        value.put("server", initServer(serviceManageFrameworkDto));
        value.put("saaslanding", initSaaslanding(serviceManageFrameworkDto));
        value.put("spring", initSpring(serviceManageFrameworkDto));
        if (ComponentLabelEnum.DEPLOYMENT.getLabel().equals(serviceManageFrameworkDto.getLabel())) {
            value.put("async", initAsync());
            value.put("docker", initDocker());
        }
        value.put("ssl", initSsl(serviceManageFrameworkDto));
        value.put("waf", initWaf(serviceManageFrameworkDto));
        value.put("cdn", initCdn(serviceManageFrameworkDto));

        return YamlUtil.jsonToYaml(value);
    }

    private Object initSsl(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        JSONObject ssl = new JSONObject();
        ssl.put("enabled", serviceManageFrameworkDto.getSslEnable());
        ssl.put("key-store-type", "JKS");
        ssl.put("key-store", serviceManageFrameworkDto.getKeyStorePath());
        ssl.put("key-store-file", serviceManageFrameworkDto.getKeyStorePath());
        ssl.put("key-store-password", serviceManageFrameworkDto.getKeyStorePwd());
        ssl.put("trust-store-type", "JKS");
        ssl.put("trust-store", serviceManageFrameworkDto.getTrustStorePath());
        ssl.put("trust-store-file", serviceManageFrameworkDto.getTrustStorePath());
        ssl.put("trust-store-password", serviceManageFrameworkDto.getTrustStorePwd());

        return ssl;
    }

    /**
     * 初始化LTS配置项 {@code saaslanding.lts}
     *
     * @param topic 主题名
     * @return LTS配置项
     */
    private Object initLts(String topic) {
        JSONObject ltsConfig = new JSONObject();
        ltsConfig.put("enabled", lts.isEnabled());
        // 不启用日志服务, 则不设置kafka或者RocketMQ参数
        if (lts.isEnabled()) {
            // 主题名使用租户code
            ltsConfig.put("topic", topic);
            ltsConfig.put("consumer", lts.getConsumer());
            ltsConfig.put("bootstrap-servers", lts.getBootstrapServers());
            if (KafkaConstant.ROCKETMQ_CONSUMER.equalsIgnoreCase(lts.getConsumer())) {
                ltsConfig.put("rocketmq-producer-group", lts.getProducerGroup());
            }
        }

        return ltsConfig;
    }

    /**
     * 构造配置数据
     * docker
     *
     * @return JSONObject
     */
    private JSONObject initDocker() {
        JSONObject api = new JSONObject();
        api.put("version", "1.41");

        JSONObject docker = new JSONObject();
        docker.put("DOCKER_HOST", "unix:///var/run/docker.sock");
        docker.put("api", api);
        docker.put("imageDirs", "/var/lib/docker/tarfile");

        return docker;
    }

    /**
     * 构造配置数据
     * async
     *
     * @return JSONObject
     */
    private JSONObject initAsync() {
        JSONObject prefix = new JSONObject();
        prefix.put("prefix", "async-service-");

        JSONObject thread = new JSONObject();
        thread.put("corePoolSize", 5);
        thread.put("maxPoolSize", 5);
        thread.put("queueCapacity", 99999);
        thread.put("name", prefix);

        JSONObject executor = new JSONObject();
        executor.put("thread", thread);

        JSONObject async = new JSONObject();
        async.put("executor", executor);

        return async;
    }

    /**
     * 构造配置数据
     * server
     *
     * @param serviceManageFrameworkDto
     *        配置信息
     * @return JSONObject
     */
    private JSONObject initServer(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        JSONObject servlet = new JSONObject();
        servlet.put("context-path", serviceManageFrameworkDto.getServletPath());

        JSONObject server = new JSONObject();
        server.put("port", serviceManageFrameworkDto.getServerPort());
        server.put("servlet", servlet);

        return server;
    }

    /**
     * 构造配置数据
     * saaslanding:mysql
     *
     * @param serviceManageFrameworkDto
     *        配置信息
     * @return JSONObject
     */
    private JSONObject initMysql(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        JSONObject mysql = new JSONObject();
        mysql.put("ip", serviceManageFrameworkDto.getRdsIp());
        mysql.put("port", serviceManageFrameworkDto.getRdsPort());
        mysql.put("database", serviceManageFrameworkDto.getRdsDatabase());
        mysql.put("username", serviceManageFrameworkDto.getRdsUserName());
        mysql.put("password", serviceManageFrameworkDto.getRdsPassword());
        mysql.put("driverClassName", "org.mariadb.jdbc.Driver");

        String template =
            "jdbc:mysql://${ip}:${port}/${database}?serverTimezone=Asia/Shanghai&permitMysqlScheme&characterEncoding=utf-8&useUnicode=true&useSSL=false&autoReconnect=true&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&nullCatalogMeansCurrent=true";
        Map<String, Object> valuesMap = new HashMap<>();
        valuesMap.put("ip", serviceManageFrameworkDto.getRdsIp());
        valuesMap.put("port", serviceManageFrameworkDto.getRdsPort());
        valuesMap.put("database", serviceManageFrameworkDto.getRdsDatabase());
        StringSubstitutor substitutor = new StringSubstitutor(valuesMap);
        String url = substitutor.replace(template);
        mysql.put("url", url);

        return mysql;
    }

    /**
     * 构造配置数据-saaslanding:oneaccess
     *
     * @param serviceManageFrameworkDto-配置信息
     * @return JSONObject
     */
    private JSONObject initOneaccess(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        JSONObject oneaccess = new JSONObject();
        oneaccess.put("domain", serviceManageFrameworkDto.getDomain());

        return oneaccess;
    }

    /**
     * 构造配置数据-saaslanding:database
     *
     * @return JSONObject
     */
    private JSONObject initDatabase(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        JSONObject hutoolId = new JSONObject();
        hutoolId.put("workerId", 0);
        hutoolId.put("dataCenterId", 0);

        JSONObject database = new JSONObject();
        database.put("isBlockAttack", false);
        database.put("p6spy", true);
        database.put("hutoolId", hutoolId);
        database.put("isNotWrite", false);
        database.put("isSeata", false);

        // 共享业务访问控制台微服务，multiTenantType 设为 DATASOURCE_AND_SCHEMA
        if (ComponentLabelEnum.TENANT.getLabel().equals(serviceManageFrameworkDto.getLabel())
            || ComponentLabelEnum.MAINTENANCE.getLabel().equals(serviceManageFrameworkDto.getLabel())
            || ComponentLabelEnum.LOG.getLabel().equals(serviceManageFrameworkDto.getLabel())) {
            database.put("multiTenantType", MultiTenantType.DATASOURCE_AND_SCHEMA);
        } else {
            database.put("multiTenantType", MultiTenantType.SCHEMA);
        }
        database.put("id-type", "HU_TOOL");

        return database;
    }

    /**
     * 构造配置数据-saaslanding
     *
     * @param serviceManageFrameworkDto-配置信息
     * @return JSONObject
     */
    private JSONObject initSaaslanding(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        JSONObject saaslanding = new JSONObject();
        saaslanding.put("oneaccess", initOneaccess(serviceManageFrameworkDto));
        saaslanding.put("database", initDatabase(serviceManageFrameworkDto));
        saaslanding.put("mysql", initMysql(serviceManageFrameworkDto));
        saaslanding.put("platformAppName", serviceManageFrameworkDto.getRdsDatabase());
        saaslanding.put("idaas", initIdaas());
        saaslanding.put("skywalking", initSkyWalking(serviceManageFrameworkDto.getSkyWalkingUiReportHost()));
        saaslanding.put("lts", initLts(serviceManageFrameworkDto.getAppName()));
        saaslanding.put("org", initOrg());
        if (ComponentLabelEnum.AUTH.getLabel().equals(serviceManageFrameworkDto.getLabel())
            || ComponentLabelEnum.JOB.getLabel().equals(serviceManageFrameworkDto.getLabel())) {
            // 给认证中心和job添加logoutUrl配置
            saaslanding.put("logoutUrl", getUiElbIpLoginUrl(serviceManageFrameworkDto));

            saaslanding.put("ingress", initIngressConfig(serviceManageFrameworkDto.getIngressClassName()));
        }
        return saaslanding;
    }

    private JSONObject initOrg() {
        JSONObject org = new JSONObject();
        String prefixCode = ResourceNamingUtil.getPrefixCode();
        org.put("prefixCode", prefixCode);
        return org;
    }

    private static JSONObject initWaf(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        JSONObject waf = new JSONObject();
        waf.put("enabled", serviceManageFrameworkDto.getWafEnabled());
        return waf;
    }

    private static JSONObject initCdn(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        JSONObject cdn = new JSONObject();
        cdn.put("enabled", serviceManageFrameworkDto.getCdnEnabled());
        return cdn;
    }

    private JSONObject initSkyWalking(String skyWalkingUiReportHost) {
        JSONObject skywalking = new JSONObject();
        skywalking.put("uiReportHost", skyWalkingUiReportHost);
        return skywalking;
    }

    private JSONObject initIdaas() {
        JSONObject configuration = new JSONObject();
        configuration.put("type", idaasType);
        return configuration;
    }

    public String getUiElbIpLoginUrl(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        boolean isHttps = serviceManageFrameworkDto.getSslEnable();
        if (isHttps) {
            return UrlConstant.HTTPS_PREFIX + environment.getProperty("saaslanding-install.elb.uiHttpsElbEip")
                + "/#/login";
        }
        return UrlConstant.HTTP_PREFIX + environment.getProperty("saaslanding-install.elb.uiElbEip") + "/#/login";
    }

    public JSONObject initIngressConfig(String ingressClassName) {
        JSONObject ingressConfig = new JSONObject();
        ingressConfig.put("ingressClassName", ingressClassName);
        return ingressConfig;
    }

    /**
     * 构造配置数据-mybatis-plus
     *
     * @return JSONObject
     */
    private JSONObject initMybatisPlus(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        JSONObject configuration = new JSONObject();
        configuration.put("cache-enabled", false);
        configuration.put("jdbc-type-for-null", "null");
        configuration.put("map-underscore-to-camel-case", true);

        JSONObject dbConfig = new JSONObject();
        // 租户微服务
        // 特殊设置
        if (!ComponentLabelEnum.TENANT.getLabel().equals(serviceManageFrameworkDto.getLabel())) {
            dbConfig.put("logic-delete-field", "isDel");
        }
        dbConfig.put("insert-strategy", "NOT_NULL");
        dbConfig.put("update-strategy", "NOT_NULL");
        dbConfig.put("where-strategy", "NOT_EMPTY");
        dbConfig.put("id-type", "INPUT");

        JSONObject globalConfig = new JSONObject();
        globalConfig.put("db-config", dbConfig);

        JSONObject mybatisPlus = new JSONObject();
        mybatisPlus.put("configuration", configuration);
        mybatisPlus.put("mapper-locations", "classpath*:mapper_**/**/*Mapper.xml");
        mybatisPlus.put("typeAliasesPackage",
            "com.huaweicloud.saaslanding.*.model;com.huaweicloud.saaslanding.basic.database.mybatis.typehandler");
        mybatisPlus.put("global-config", globalConfig);

        return mybatisPlus;
    }

    /**
     * 构造配置数据-logging
     *
     * @return JSONObject
     */
    private JSONObject initLogging() {
        JSONObject level = new JSONObject();
        level.put("root", "info");
        level.put("com.baomidou.dynamic", "info");

        JSONObject file = new JSONObject();
        file.put("path", "logs");

        JSONObject logging = new JSONObject();
        logging.put("level", level);
        logging.put("file", file);

        return logging;
    }

    /**
     * 构造配置数据-spring:datasource:druid:filter
     *
     * @return JSONObject
     */
    private JSONObject initFilter() {
        JSONObject config = new JSONObject();
        config.put("multiStatementAllow", true);
        config.put("commentAllow", true);
        config.put("noneBaseStatementAllow", true);

        JSONObject wall = new JSONObject();
        wall.put("config", config);
        wall.put("enabled", true);

        JSONObject filter = new JSONObject();
        filter.put("wall", wall);

        return filter;
    }

    /**
     * 构造配置数据 spring:datasource
     *
     * @return JSONObject
     */
    private JSONObject initDatasource(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        JSONObject dynamic = new JSONObject();
        dynamic.put("enabled", true);

        JSONObject mysql = new JSONObject();
        mysql.put("usePingMethod", false);

        JSONObject druid = new JSONObject();
        druid.put("max-pool-prepared-statement-per-connection-size", 20);
        druid.put("minIdle", 10);
        druid.put("initialSize", 10);
        druid.put("test-while-idle", true);
        druid.put("time-between-eviction-runs-millis", 60000);
        druid.put("validation-query", "SELECT 'x'");
        druid.put("filters", "stat,wall");
        druid.put("max-wait", 60000);

        String template =
            "jdbc:mysql://${ip}:${port}/${database}?serverTimezone=Asia/Shanghai&permitMysqlScheme&characterEncoding=utf-8&useUnicode=true&useSSL=false&autoReconnect=true&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&nullCatalogMeansCurrent=true";
        Map<String, Object> valuesMap = new HashMap<>();
        valuesMap.put("ip", serviceManageFrameworkDto.getRdsIp());
        valuesMap.put("port", serviceManageFrameworkDto.getRdsPort());
        valuesMap.put("database", serviceManageFrameworkDto.getRdsDatabase());
        StringSubstitutor substitutor = new StringSubstitutor(valuesMap);
        String url = substitutor.replace(template);

        druid.put("url", url);
        druid.put("filter", initFilter());
        druid.put("username", serviceManageFrameworkDto.getRdsUserName());
        druid.put("password", serviceManageFrameworkDto.getRdsPassword());
        druid.put("test-on-borrow", false);
        druid.put("db-type", "mysql");
        druid.put("enable", true);
        druid.put("pool-prepared-statements", true);
        druid.put("mysql", mysql);
        druid.put("min-evictable-idle-time-millis", 300000);
        druid.put("driver-class-name", "org.mariadb.jdbc.Driver");
        druid.put("maxActive", 200);
        druid.put("test-on-return", false);

        generateDynamicDatasourceConfig(serviceManageFrameworkDto, dynamic, url);

        JSONObject datasource = new JSONObject();
        datasource.put("druid", druid);
        datasource.put("dynamic", dynamic);

        return datasource;
    }

    /**
     * 生成动态数据源配置项
     *
     * @param serviceManageFrameworkDto-CSE配置项基本信息
     * @param dynamic-动态数据源配置节
     * @param url-数据库JDBC连接串
     */
    private void generateDynamicDatasourceConfig(ServiceManageFrameworkDto serviceManageFrameworkDto,
        JSONObject dynamic, String url) {

        // 租户&运维&日志微服务需要设置动态数据源
        if (ComponentLabelEnum.TENANT.getLabel().equals(serviceManageFrameworkDto.getLabel())
            || ComponentLabelEnum.MAINTENANCE.getLabel().equals(serviceManageFrameworkDto.getLabel())
            || ComponentLabelEnum.LOG.getLabel().equals(serviceManageFrameworkDto.getLabel())) {
            dynamic.put("primary", "master");
            JSONObject dynamicDatasource = new JSONObject();
            JSONObject master = new JSONObject();
            master.put("ip", serviceManageFrameworkDto.getRdsIp());
            master.put("port", serviceManageFrameworkDto.getRdsPort());
            master.put("driverClassName", "org.mariadb.jdbc.Driver");
            master.put("database", serviceManageFrameworkDto.getRdsDatabase());
            master.put("url", url);
            master.put("username", serviceManageFrameworkDto.getRdsUserName());
            master.put("password", serviceManageFrameworkDto.getRdsPassword());

            dynamicDatasource.put("master", master);
            dynamic.put("datasource", dynamicDatasource);
        }
    }

    /**
     * 构造配置数据spring
     *
     * @return JSONObject
     */
    private JSONObject initSpring(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        JSONObject application = new JSONObject();
        application.put("name", serviceManageFrameworkDto.getServiceName());

        JSONObject main = new JSONObject();
        main.put("allow-bean-definition-overriding", true);

        JSONObject autoconfigure = new JSONObject();
        autoconfigure.put("exclude", "org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration");

        JSONObject spring = new JSONObject();
        spring.put("application", application);
        spring.put("datasource", initDatasource(serviceManageFrameworkDto));
        spring.put("main", main);
        spring.put("autoconfigure", autoconfigure);
        spring.put("data", initSpringData());

        if (ComponentLabelEnum.JOB.getLabel().equals(serviceManageFrameworkDto.getLabel())) {
            spring.put("quartz", initQuartz(serviceManageFrameworkDto));
        }
        if (ComponentLabelEnum.DEPLOYMENT.getLabel().equals(serviceManageFrameworkDto.getLabel())
            || ComponentLabelEnum.JOB.getLabel().equals(serviceManageFrameworkDto.getLabel())) {
            spring.put("http", initHttp());
            spring.put("servlet", initServlet());
        } else if (ComponentLabelEnum.UPGRADE.getLabel().equals(serviceManageFrameworkDto.getLabel())) {
            // 升级服务中添加flyway的配置
            JSONObject flyway = new JSONObject();
            flyway.put("enabled", "false");
            spring.put("flyway", flyway);
        }

        return spring;
    }

    /**
     * 初始化data
     *
     * @return data配置项
     */
    private JSONObject initSpringData() {
        JSONObject data = new JSONObject();
        data.put("redis", initRedis());
        return data;
    }

    /**
     * 构造配置数据
     * spring.data.redis
     *
     * @return JSONObject
     */
    private JSONObject initRedis() {
        JSONObject redisConfig = new JSONObject();

        if (RedisServerTypeEnum.isValidatedType(dcs.getType())) {
            JSONObject redisCluster = new JSONObject();
            redisCluster.put("nodes", dcs.getNodes());
            redisConfig.put("cluster", redisCluster);
            redisConfig.put("type", dcs.getType());
        } else {
            log.error("redis配置错误！！！");
            throw new BizException(ExceptionCode.ILLEGAL_ARGUMENT_EX);
        }

        if (dcs.getTimeout() != null) {
            redisConfig.put("timeout", dcs.getTimeout());
        }
        if (dcs.getPassword() != null) {
            QueryWrapper<RedisInfo> redisInfoQueryWrapper = new QueryWrapper<>();
            redisInfoQueryWrapper.eq("is_del", 0);
            RedisInfo redisInfo = redisInfoBaseMapper.selectOne(redisInfoQueryWrapper);
            String encryptedPassword = "ENC(" + redisInfo.getPassword() + ")";
            redisConfig.put("password", encryptedPassword);
        }

        return redisConfig;
    }

    /**
     * 构造配置数据
     * spring:http
     *
     * @return JSONObject
     */
    private JSONObject initHttp() {
        JSONObject multipart = new JSONObject();
        multipart.put("enabled", true);
        multipart.put("max-file-size", "10240MB");
        multipart.put("max-request-size", "10240MB");

        JSONObject http = new JSONObject();
        http.put("multipart", multipart);

        return http;
    }

    /**
     * 构造配置数据
     * spring:servlet
     *
     * @return JSONObject
     */
    private JSONObject initServlet() {
        JSONObject multipart = new JSONObject();
        multipart.put("max-file-size", "10240MB");
        multipart.put("max-request-size", "10240MB");

        JSONObject servlet = new JSONObject();
        servlet.put("multipart", multipart);

        return servlet;
    }

    /**
     * 构造配置数据
     * spring:quartz
     *
     * @return JSONObject
     */
    private JSONObject initQuartz(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        String template = "properties:\n" + "        org:\n" + "          quartz:\n" + "            dataSource:\n"
            + "              myDS:\n" + "                driver: ${driverClassName}\n"
            + "                user: ${username}\n" + "                password: ${password}\n"
            + "                URL: jdbc:mysql://${ip}:${port}/${quartz}?serverTimezone=Asia/Shanghai&permitMysqlScheme&characterEncoding=utf8&useUnicode=true&useSSL=false&autoReconnect=true&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&nullCatalogMeansCurrent=true\n"
            + "                provider: hikaricp\n" + "            jobStore:\n"
            + "              clusterCheckinInterval: 10000\n" + "              isClustered: true\n"
            + "              class: org.quartz.impl.jdbcjobstore.JobStoreTX\n"
            + "              driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate\n"
            + "              tablePrefix: qrtz_\n" + "              useProperties: false\n"
            + "              dataSource: myDS\n" + "            scheduler:\n"
            + "              instanceName: quartzScheduler\n" + "              instanceId: AUTO\n"
            + "            threadPool:\n" + "              class: org.quartz.simpl.SimpleThreadPool\n"
            + "              threadCount: 10\n" + "              threadPriority: 5\n"
            + "              threadsInheritContextClassLoaderOfInitializingThread: true";
        Map<String, Object> valuesMap = new HashMap<>();
        valuesMap.put("ip", serviceManageFrameworkDto.getRdsIp());
        valuesMap.put("port", serviceManageFrameworkDto.getRdsPort());
        valuesMap.put("quartz", serviceManageFrameworkDto.getRdsDatabase());
        valuesMap.put("username", serviceManageFrameworkDto.getRdsUserName());
        valuesMap.put("password", serviceManageFrameworkDto.getRdsPassword());
        valuesMap.put("driverClassName", "org.mariadb.jdbc.Driver");
        StringSubstitutor substitutor = new StringSubstitutor(valuesMap);
        String str = substitutor.replace(template);
        Yaml yaml = new Yaml();
        return yaml.loadAs(str, JSONObject.class);
    }

    /**
     * 【灰度/蓝绿升级配置项】
     * 【请求体】，用于创建CSE微服务级配置项
     *
     * @return String
     */
    public CseConfigCreateRequest createCseUpgradeConfigJson(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        CseConfigCreateRequest configCreateRequest =
            getCseBaseRequestJSONObject(serviceManageFrameworkDto, ConfigFilePrefixEnum.GRAY_ROUTE.getPrefix());

        configCreateRequest.setValue(initGrayRouteValue(ServiceManageFrameTypeEnum.CSE.getName()));

        return configCreateRequest;
    }

    /**
     * 构造【灰度/蓝绿升级】【配置数据】
     */
    public String initGrayRouteValue(String serviceManageFrame) {
        JSONObject routeRule = new JSONObject();

        JSONObject servicecomb = new JSONObject();
        servicecomb.put("routeRule", routeRule);

        JSONObject value = new JSONObject();
        if (ServiceManageFrameTypeEnum.NACOS.getName().equals(serviceManageFrame)) {
            value.put("graynacos", servicecomb);
        } else if (ServiceManageFrameTypeEnum.CSE.getName().equals(serviceManageFrame)) {
            value.put("servicecomb", servicecomb);
        }

        return YamlUtil.jsonToYaml(value);
    }

    public CseConfigCreateRequest initCseDynamicRoute(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        CseConfigCreateRequest configCreateRequest =
            getCseBaseRequestJSONObject(serviceManageFrameworkDto, ConfigFilePrefixEnum.DYNAMIC_ROUTE.getPrefix());

        configCreateRequest.setValue(initDynamicRouteValue(serviceManageFrameworkDto));

        return configCreateRequest;
    }

    public CseConfigCreateRequest initCseDynamicRouteLink(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        CseConfigCreateRequest configCreateRequest =
            getCseBaseRequestJSONObject(serviceManageFrameworkDto, ConfigFilePrefixEnum.DYNAMIC_ROUTE_LINK.getPrefix());

        JSONObject value = new JSONObject();
        value.put(RouteLinkConstant.ROUTE_LINK, initDynamicRouteLinkValue());

        configCreateRequest.setValue(YamlUtil.jsonToYaml(value));

        return configCreateRequest;
    }

    /**
     * 构造动态路由配置
     */
    public String initDynamicRouteValue(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        JSONObject gateway = new JSONObject();
        gateway.put("routes", initRoutes(serviceManageFrameworkDto));

        JSONObject cloud = new JSONObject();
        cloud.put("gateway", gateway);

        JSONObject spring = new JSONObject();
        spring.put("cloud", cloud);

        JSONObject value = new JSONObject();
        value.put("spring", spring);

        if (swaggerEnabled) {
            JSONObject swaggerUi = new JSONObject();
            swaggerUi.put("use-root-path", true);
            swaggerUi.put("urls", initSwaggerUrls(serviceManageFrameworkDto));

            JSONObject springDoc = new JSONObject();
            springDoc.put("swagger-ui", swaggerUi);
            value.put("springdoc", springDoc);
        }
        return YamlUtil.jsonToYaml(value);
    }

    public List<JSONObject> initSwaggerUrls(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        List<JSONObject> urls = new ArrayList<>();
        JSONObject tenant = new JSONObject();
        tenant.put("name", serviceManageFrameworkDto.getTenantName());
        tenant.put("url", serviceManageFrameworkDto.getTenantPath().replace("**", SWAGGER_API));
        urls.add(tenant);

        JSONObject authority = new JSONObject();
        authority.put("name", serviceManageFrameworkDto.getAuthorityName());
        authority.put("url", serviceManageFrameworkDto.getAuthorityPath().replace("**", SWAGGER_API));
        urls.add(authority);

        JSONObject deployment = new JSONObject();
        deployment.put("name", serviceManageFrameworkDto.getDeploymentName());
        deployment.put("url", serviceManageFrameworkDto.getDeploymentPath().replace("**", SWAGGER_API));
        urls.add(deployment);

        JSONObject upgrade = new JSONObject();
        upgrade.put("name", serviceManageFrameworkDto.getUpgradeName());
        upgrade.put("url", serviceManageFrameworkDto.getUpgradePath().replace("**", SWAGGER_API));
        urls.add(upgrade);

        JSONObject maintenance = new JSONObject();
        maintenance.put("name", serviceManageFrameworkDto.getMaintenanceName());
        maintenance.put("url", serviceManageFrameworkDto.getMaintenancePath().replace("**", SWAGGER_API));
        urls.add(maintenance);

        JSONObject auth = new JSONObject();
        auth.put("name", serviceManageFrameworkDto.getAuthName());
        auth.put("url", serviceManageFrameworkDto.getAuthPath().replace("**", SWAGGER_API));
        urls.add(auth);

        JSONObject integrated = new JSONObject();
        integrated.put("name", serviceManageFrameworkDto.getIntegratedName());
        integrated.put("url", serviceManageFrameworkDto.getIntegratedPath().replace("**", SWAGGER_API));
        urls.add(integrated);

        JSONObject log = new JSONObject();
        log.put("name", serviceManageFrameworkDto.getLogName());
        log.put("url", serviceManageFrameworkDto.getLogPath().replace("**", SWAGGER_API));
        urls.add(log);

        JSONObject measurement = new JSONObject();
        measurement.put("name", serviceManageFrameworkDto.getMeasurementName());
        measurement.put("url", serviceManageFrameworkDto.getMeasurementPath().replace("**", SWAGGER_API));
        urls.add(measurement);

        JSONObject operation = new JSONObject();
        operation.put("name", serviceManageFrameworkDto.getOperationName());
        operation.put("url", serviceManageFrameworkDto.getOperationPath().replace("**", SWAGGER_API));
        urls.add(operation);

        JSONObject job = new JSONObject();
        job.put("name", serviceManageFrameworkDto.getJobName());
        job.put("url", serviceManageFrameworkDto.getJobPath().replace("**", SWAGGER_API));
        urls.add(job);

        return urls;
    }

    /**
     * 构造全链路灰度路由文件
     *
     * @return 文件内容
     */
    public String initDynamicRouteLinkValue() {

        JSONObject value = new JSONObject();
        value.put("routeRules", "");

        return YamlUtil.jsonToYaml(value);
    }

    private CseConfigCreateRequest getCseBaseRequestJSONObject(ServiceManageFrameworkDto serviceManageFrameworkDto,
        String keyPrefix) {
        String service = serviceManageFrameworkDto.getServiceName();
        Map<String, String> labels = new HashMap<>();
        labels.put("app", serviceManageFrameworkDto.getAppName());
        labels.put("environment", "");
        labels.put("service", service);

        CseConfigCreateRequest configCreateRequest = new CseConfigCreateRequest();
        if (ConfigFilePrefixEnum.DYNAMIC_ROUTE_LINK.getPrefix().equals(keyPrefix)) {
            configCreateRequest.setKey(ConfigNameUtil.getDynamicRouteLink());
        } else {
            configCreateRequest.setKey(ConfigNameUtil.get(keyPrefix, serviceManageFrameworkDto.getActive(), service));
        }
        configCreateRequest.setValueType(FileExtensionEnum.YAML.getName());
        configCreateRequest.setStatus("enabled");
        configCreateRequest.setLabels(labels);
        return configCreateRequest;
    }
}
